package model;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import config.Debug;
import config.Helper;
import config.Settings;

/**
 * 
 * @author y62wang
 */
public class Playlist extends ArrayList<PlaylistRecord> implements Comparable<Playlist> {

	// playlist type constants, currently not implemented
	public static final int REGULAR = 1;
	public static final int FREQUENCY = 2;
	public static final int FIXED_TIME = 3;

	private int id;
	private String name;
	private int playlistOrder;
	private boolean active;
	private int type;

	// precondition: none
	// postcondition: a playlist with the given id is fetched from database with
	// all the records
	public Playlist(int id) {
		this.createPlaylistFromDatabaseById(id);
		this.generateRecords();
	}

	// precondition: none
	// postcondition: a playlist object is create from database with no records
	private void createPlaylistFromDatabaseById(int id) {
		String sql = String.format("SELECT * FROM `playlist` WHERE `playlist_id`='%1$s';", id);
		Connection conn = Settings.getLocalDatabaseConnection();
		ResultSet result = null;
		Statement stmt = null;
		try {
			int numResults = Helper.getNumberOfResults(sql);
			if (numResults <= 0) {
				// throw new
				// com.mysql.jdbc.exceptions.MySQLDataException("There is no playlist with id: "
				// + id);
				Debug.log(Playlist.class.getName() + ": There is no playlist with id: " + id, Debug.WARNING_LEVEL);
				return;
			}
			stmt = conn.createStatement();
			result = stmt.executeQuery(sql);
			result.first();
			this.id = id;
			this.name = result.getString("playlist_name");
			this.playlistOrder = result.getInt("playlist_order");
			this.active = (1 == result.getInt("playlist_active")) ? true : false;
		} catch (SQLException ex) {
			Debug.log(Playlist.class.getName() + ": SQLException: " + ex.getMessage());
			// Logger.getLogger(Playlist.class.getName()).log(Level.SEVERE,
			// null, ex);
		} finally {
			try {
				if (result != null) {
					result.close();
				}
				if (stmt != null) {
					stmt.close();
				}
			} catch (SQLException ex) {
				Debug.log(Playlist.class.getName() + ": SQLException: " + ex.getMessage());
			}

		}
	}

	// precondition: none
	// postcondition: this playlist is empty
	private void removeAll() {
		while (!this.isEmpty()) {
			this.remove(0);
		}
	}

	// precondition: this.id is set
	// postcondition: this playlist is populated with all the playlist records
	// that are associated with this playlist
	private void generateRecords() {
		this.removeAll();
		String sql = String.format(
				"SELECT DISTINCT playlist_record_id FROM `playlist_record` WHERE `playlist_id`='%1$s' AND `active`=1 ORDER BY record_order;", id);
		Connection conn = Settings.getLocalDatabaseConnection();
		ResultSet result = null;
		Statement stmt = null;
		try {
			int numResults = Helper.getNumberOfResults(sql);
			if (numResults <= 0) {
				// there are no records
				return;
			}
			stmt = conn.createStatement();
			result = stmt.executeQuery(sql);
			result.beforeFirst();

			while (result.next() == true) {
				// invariant: cursor is pointing the next playlist record id
				int playlistRecordId = result.getInt("playlist_record_id");
				PlaylistRecord pr = new PlaylistRecord(playlistRecordId);
				this.add(pr);
			}
			// assertion: all playlist record associated with this.id is added
			// to the playlist
		} catch (SQLException ex) {
			Logger.getLogger(Playlist.class.getName()).log(Level.SEVERE, null, ex);
		} finally {
			try {
				if (result != null) {
					result.close();
				}
				if (stmt != null) {
					stmt.close();
				}
			} catch (SQLException ex) {
				Logger.getLogger(Playlist.class.getName()).log(Level.SEVERE, null, ex);
			}

		}

	}

	// precondition: type is not null
	// postcondition: the playlist type is set.
	public void setTypeByName(String type) {
		if (type.equalsIgnoreCase("frequency")) {
			this.type = Playlist.FREQUENCY;
		} else if (type.equalsIgnoreCase("fixedtime")) {
			this.type = Playlist.FIXED_TIME;
		} else {
			this.type = Playlist.REGULAR;
		}
	}

	@Override
	// precondition: none
	// postcondition: returns true if o is the same playlist as this one
	public boolean equals(Object o) {
		// [null instanceof AnyThing] will return false
		if (o instanceof Playlist && ((Playlist) (o)).getId() == this.getId()) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public int hashCode() {
		return this.getId();
	}

	// getter
	private int getId() {
		return this.id;
	}

	@Override
	public String toString() {
		return String.format("[Playlist:%1$d] - %2$s sort_order: %3$d active: %4$b", this.getId(), this.name, this.playlistOrder, this.active);
	}

	@Override
	// implementation of the Comparable interface
	// precondition: none
	// postcondition: returns a negative number if this playlist's order is less
	// than the playlist passed in
	// returns a positive number if this playlist's order is greater than the
	// playlist passed in
	public int compareTo(Playlist p) {
		if (p.getPlaylistOrder() == this.getPlaylistOrder()) {
			return this.id - p.getId();
		} else {
			return this.getPlaylistOrder() - p.getPlaylistOrder();
		}
	}

	// getter
	public boolean isActive() {
		return active;
	}

	// getter
	public String getName() {
		return name;
	}

	// getter
	public int getPlaylistOrder() {
		return playlistOrder;
	}

	// getter
	public int getType() {
		return type;
	}

	public static void main(String[] args) {
		Playlist plist = new Playlist(119);
		System.out.println(plist);
	}
}
